package com.mofum.scope.processor.impl;

import com.mofum.scope.common.model.Permission;
import com.mofum.scope.common.model.Scope;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Invocation;
import com.mofum.scope.processor.IRestructureProcessor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 默认重构SQL 处理器
 *
 * @author yuyang@qxy37.com
 * @since 2019-03-19
 **/
public class DefaultRestructureProcessor implements IRestructureProcessor {
    @Override
    public BoundSql process(Invocation invocation, BoundSql permissionSql, Permission permission) {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        BoundSql boundSql;
        if (args.length == 4) {
            boundSql = ms.getBoundSql(parameter);
        } else {
            boundSql = (BoundSql) args[5];
        }
        return restructureSql(ms, permission, boundSql);
    }

    /**
     * 重构SQL
     *
     * @param ms         语句
     * @param permission 权限内容
     * @param boundSql   SQL内容
     */
    private BoundSql restructureSql(MappedStatement ms, Permission permission, BoundSql boundSql) {

        try {

            //语句
            Select originSelect = (Select) CCJSqlParserUtil.parse(boundSql.getSql());

            PlainSelect originPlainSelect = (PlainSelect) originSelect.getSelectBody();


            //包装权限内容
            wrapperPermission(originPlainSelect, permission);

            BoundSql newSql = new BoundSql(ms.getConfiguration(), originPlainSelect.toString(), boundSql.getParameterMappings(), boundSql.getParameterObject());

            return newSql;

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 包装权限内容SQL
     *
     * @param resultPlainSelect 结果标准查询
     * @param permission
     */
    private void wrapperPermission(PlainSelect resultPlainSelect, Permission permission) {
        //权限为空不拼装
        if (permission == null || permission.getScopeCollections() == null || permission.getScopeCollections().size() == 0) {
            return;
        }

        List<Scope> scopes = permission.getScopeCollections();


        //Table  --  范围
        Map<String, List<Scope>> tableMap = new HashMap<>();

        for (Scope scope : scopes) {

            List<Scope> list = null;

            if (scope.getTableName() == null) {
                list = tableMap.get("");

            } else {
                list = tableMap.get(scope.getTableName());
            }

            if (list == null) {
                list = new ArrayList<>();
                tableMap.put(scope.getTableName(), list);
            }

            list.add(scope);

        }

        for (String table : tableMap.keySet()) {

            wrapperScope(resultPlainSelect, table, tableMap.get(table));

        }

    }

    private  void wrapperScope(PlainSelect resultPlainSelect, String table, List<Scope> scopes) {
        // Column - Scopes
        Map<String, List<String>> scopesMap = new HashMap<>();

        for (Scope scope : scopes) {

            if (scope.getColumn() == null || scope.getColumn().trim().equals("")) {
                continue;
            }

            List<String> data = scopesMap.get(scope.getColumn());

            if (data == null) {
                List<String> list = new ArrayList<>();
                scopesMap.put(scope.getColumn(), list);
            }
            data = scopesMap.get(scope.getColumn());

            data.add(scope.getId());
        }

        for (String column : scopesMap.keySet()) {

            wrapperScopes(resultPlainSelect, table, column, scopesMap.get(column));

        }
    }

    private void wrapperScopes(PlainSelect resultPlainSelect, String tableName, String columnName, List<String> scopes) {
        //拼装条件

        InExpression inExpression = new InExpression();
        Column column = new Column();

        column.setColumnName(columnName);

        column.setTable(new Table(tableName));

        inExpression.setLeftExpression(column);

        List<Expression> list = convertPermissionList(scopes);

        inExpression.setRightItemsList(new ExpressionList(list));

        Expression expression = resultPlainSelect.getWhere();

        if(expression == null){
            resultPlainSelect.setWhere(inExpression);
            return;
        }

        Parenthesis parenthesis = new Parenthesis(expression);

        AndExpression andExpression = new AndExpression(parenthesis, inExpression);

        resultPlainSelect.setWhere(andExpression);
    }

    /**
     * 转换权限list
     *
     * @param scopes 权限范围内容
     * @return
     */
    private List<Expression> convertPermissionList(List<String> scopes) {

        List<Expression> expressions = new ArrayList<>();

        for (String scope : scopes) {
            expressions.add(new StringValue(scope));
        }
        return expressions;

    }

    public static void main(String[] args) throws JSQLParserException {
        DefaultRestructureProcessor defaultRestructureProcessor =  new DefaultRestructureProcessor();

        //语句
        Select originSelect = (Select) CCJSqlParserUtil.parse("select * from tb Order By col desc Limit 1");

        PlainSelect originPlainSelect = (PlainSelect) originSelect.getSelectBody();

        Permission permission = new Permission();

        List<Scope> scopes = new ArrayList<>();

        Scope scope = new Scope();

        scope.setTableName("");

        scope.setColumn("wmsId");

        scope.setId("1235467");

        Scope scope2 = new Scope();

        scope2.setTableName("t2");

        scope2.setColumn("shopId");

        scope2.setId("1235467");

        scopes.add(scope);
        scopes.add(scope2);

        permission.setScopeCollections(scopes);

        defaultRestructureProcessor.wrapperPermission(originPlainSelect,permission);

        System.out.println(originPlainSelect.toString());
    }
}
